/**
 * =============================================
 * 自定义触底加载钩子函数
 * 创作者：学答也
 * 创建日期：2024-05-15 10:58:58
 * 联系方式：2304493354@qq.com
 * =============================================
 */
import {
	reactive,
	ref,
	toRef
} from 'vue'
/**
 * 自定义触底加载钩子函数，用于实现页面滚动到底部时自动加载更多数据的功能 
 * 
 * @template T - 数据类型 
 * @param {Function} func - 异步请求函数，接收分页参数并返回Promise 
 * @param {Object} [options={}] - 配置选项 
 * @param {boolean} [options.immediate=true] - 是否在组件加载时立即执行请求 
 * @param {boolean} [options.pullDown=false] - 是否启用下拉刷新功能 
 * @param {T[]} [options.initialData=[]] - 初始化数据 
 * @param {boolean} [options.onShow=false] - 是否在页面显示时重置并加载数据 
 * @param {number} [options.pageSize=10] - 每页数据条数 
 * @returns {Object} 包含数据、状态和操作方法的对象 
 * @property {string} error - 请求错误信息 
 * @property {T[]} data - 加载的数据列表 
 * @property {'loadmore'|'loading'|'nomore'} status - 当前加载状态 
 * @property {Function} run - 手动触发加载的方法 
 * @property {Function} reset - 重置加载状态和数据的方法 
 * 
 * @example 
 * const { data, status, reset } = useReachBottom(async (params) => {
 *   const res = await uni.request({  url: '/api/list', data: params })
 *   return res.data  
 * }, { pageSize: 15, pullDown: true })
 */
export default function useReachBottom(func, options = {}) {
	// 合并默认配置 
	const config = {
		immediate: true,
		pullDown: false,
		initialData: [],
		onShow: false,
		pageSize: 10,
		...options
	}
	/** @type {Object} 页面参数对象 */
	const pageParams = reactive({})

	/** @type {import('vue').Ref<string>} 请求错误信息 */
	const error = ref('')

	/** @type {import('vue').Ref<any[]>} 加载的数据列表 */
	const data = ref([...config.initialData])

	/** @type {Object} 请求状态对象 */
	const state = reactive({
		/** @type {number} 当前页码 */
		page: 1,
		/** @type {number} 数据总数 */
		total: 0,
		/** @type {'loadmore'|'loading'|'nomore'} 加载状态 */
		status: 'loadmore'
	})
	/**
	 * 执行数据加载请求 
	 * @param {Function} [callback] - 请求完成后的回调函数 
	 */
	const run = async (callback) => {
		if (state.status === 'loading') return

		try {
			state.status = 'loading'
			const params = {
				page: state.page,
				page_size: config.pageSize,
				...pageParams
			}

			const res = await func(params)
			const newData = res?.data || []

			// 更新数据：如果是第一页则替换，否则追加 
			data.value = state.page === 1 ? newData : [...data.value, ...newData]
			state.total = res?.total || 0

			// 更新加载状态 
			state.status = state.page * config.pageSize >= state.total ? 'nomore' : 'loadmore'
		} catch (err) {
			error.value = err.message || '请求失败'
			state.status = 'loadmore'
		} finally {
			callback?.()
		}
	}
	// 下拉刷新处理 
	onPullDownRefresh(() => {
		if (config.pullDown) {
			state.page = 1
			run(() => uni.stopPullDownRefresh())
		}
	})
	// 触底加载处理 
	onReachBottom(() => {
		if (state.status !== 'loadmore') return
		state.page += 1
		run()
	})
	// 页面加载处理 
	onLoad((params) => {
		Object.assign(pageParams, params)
		if (!config.onShow && config.immediate) run()
	})
	// 页面显示处理 
	onShow(() => {
		if (config.onShow) reset()
	})
	/**
	 * 重置加载状态和数据 
	 */
	const reset = () => {
		state.page = 1
		state.total = 0
		data.value = [...config.initialData]
		error.value = ''
		state.status = 'loadmore'
		run()
	}
	return {
		error,
		data,
		status: toRef(state, 'status'),
		run,
		reset
	}
}